﻿using System.Collections.Generic;
using Baula.TextGen.Framework.Sections;
using Baula.TextGen.Framework.Tools;

namespace Baula.TextGen.Framework
{
    public class Part
    {
        private readonly PartTemplate _partTemplate;
        private readonly ValuesForPlaceholders _valuesForPlaceholders;
        private readonly Dictionary<PlaceholderSection, List<string>> _placeholderSectionInstances;

        public Part(PartTemplate partTemplate)
        {
            _partTemplate = partTemplate;
            _valuesForPlaceholders = new ValuesForPlaceholders(partTemplate.Placeholders);
            _placeholderSectionInstances = CreatePlaceholderSectionInstances(partTemplate);
        }

        private Dictionary<PlaceholderSection, List<string>> CreatePlaceholderSectionInstances(PartTemplate partTemplate)
        {
            var placeholderSectionInstances = new Dictionary<PlaceholderSection, List<string>>();
            foreach (var placeholderSection in partTemplate.PlaceholderSections)
            {
                placeholderSectionInstances.Add(placeholderSection.Value, new List<string>());
            }
            return placeholderSectionInstances;
        }

        internal PartTemplate PartTemplate
        {
            get { return _partTemplate; }
        }

        internal string RenderToString(RenderMode renderMode)
        {
            var lineCollector = new LineCollector();

            foreach (var section in PartTemplate.Sections)
            {
                var contentSection = section as ContentSection;
                if (contentSection != null)
                {
                    var sectionLiteralContent = ReplacePlaceholders(ValuesForPlaceholders, contentSection.Content,
                                                                    PartTemplate.Placeholders);
                    lineCollector.AppendAsNewLine(sectionLiteralContent);
                }
                var placeholderSection = section as PlaceholderSection;
                if (placeholderSection != null)
                {
                    if (renderMode == RenderMode.Heading)
                    {
                        lineCollector.AppendAsNewLine(placeholderSection.HeadingLine);
                    }
                    foreach (var relocatedSectionLiteralContent in PlaceholderSectionInstances[placeholderSection])
                    {
                        lineCollector.AppendAsNewLine(relocatedSectionLiteralContent);
                    }
                    if (renderMode == RenderMode.Updatable)
                    {
                        lineCollector.AppendAsNewLine(placeholderSection.HeadingLine);
                    }
                }
            }

            return lineCollector.ToString();
        }

        public ValuesForPlaceholders ValuesForPlaceholders
        {
            get { return _valuesForPlaceholders; }
        }

        internal void AppendToPlaceholderSection(RelocationSection relocationSection, Part part)
        {
            var literalContent = ReplacePlaceholders(part.ValuesForPlaceholders, relocationSection.Content, part.PartTemplate.Placeholders);
            AppendToPlaceholderSectionLiteral(relocationSection, literalContent);
        }

        private void AppendToPlaceholderSectionLiteral(RelocationSection relocationSection, string literalContent)
        {
            PlaceholderSectionInstances[relocationSection.RelocateTo].Add(literalContent);
        }

        private Dictionary<PlaceholderSection, List<string>> PlaceholderSectionInstances
        {
            get { return _placeholderSectionInstances; }
        }

        private string ReplacePlaceholders(ValuesForPlaceholders valuesForPlaceholders, string templateContent,
                                           IEnumerable<string> placeholders)
        {
            var content = templateContent;
            foreach (var placeholder in placeholders)
            {
                if (!valuesForPlaceholders.Contains(placeholder))
                {
                    throw new MissingPlaceholderValueException(placeholder);
                }
                content = content.Replace(GetToken(placeholder), valuesForPlaceholders[placeholder]);
            }
            return content;
        }

        private string GetToken(string placeholder)
        {
            return string.Format("%{0}%", placeholder);
        }
    }
}